#include "FrameBuffer.h"

namespace egg{

    FrameBuffer::FrameBuffer(uint32 w,uint32 h){
        mWidth=w;
        mHeight=h;
        glGenFramebuffers(1, &mID);
        RHILogError("FrameBuffer::construct");
    }

    FrameBuffer::~FrameBuffer(){
        glDeleteFramebuffers(1,&mID);
        RHILogError("FrameBuffer::destruct");
    }

    void FrameBuffer::resize(uint32 w,uint32 h){
        if(mWidth==w&&mHeight==h)
            return;
        mWidth=w;
        mHeight=h;
        for(int i=0;i<mColors.size();i++){
            mColors[i]->resize(w,h);
        }
        if(mDepthBuffer!=0){
            mDepthBuffer->resize(w,h);
        }
        if(mDepthTexture!=0)
            mDepthTexture->resize(w,h);
    }

    void FrameBuffer::attachColor(TexturePtr tex){
        checkDimension(tex);
        StateCache::setFrameBuffer(mID);
        glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            mColors.size()+GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            tex->getID(),
            0);
        mDrawBuffers.push_back(mColors.size()+GL_COLOR_ATTACHMENT0);
        glDrawBuffers(mDrawBuffers.size(),&mDrawBuffers[0]);
        mColors.push_back(tex);
        StateCache::setFrameBuffer(0);
        RHILogError("FrameBuffer::attachColor");
    }

    void FrameBuffer::setColor(uint32 slot,TexturePtr tex){
        checkDimension(tex);
        if(slot<mColors.size()){
            StateCache::setFrameBuffer(mID);
            glBindTexture(GL_TEXTURE_2D,tex->getID());
            glFramebufferTexture2D(
                GL_FRAMEBUFFER,
                slot+GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D,
                tex->getID(),
                0);
            StateCache::setFrameBuffer(0);
            glBindTexture(GL_TEXTURE_2D,0);
            RHILogError("FrameBuffer::setColor");
            mColors[slot]=tex;
        }else{
            LogMgr->logMessage("framebuffer slot out of range");
        }
    }

    void FrameBuffer::setDepthTexture(TexturePtr depth){
        if(mDepthBuffer!=0)
            mDepthBuffer=0;
        mDepthTexture=depth;
        StateCache::setFrameBuffer(mID);
        glBindTexture(GL_TEXTURE_2D,depth->getID());
        glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            GL_DEPTH_ATTACHMENT,
            GL_TEXTURE_2D,
            depth->getID(),
            0);
        if(depth->getPixelFormat().mFormat==PixelFormat::D24S8){
            glFramebufferTexture2D(
                GL_FRAMEBUFFER,
                GL_STENCIL_ATTACHMENT,
                GL_TEXTURE_2D,
                depth->getID(),
                0);
        }
        GLenum check=glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if(check!=GL_FRAMEBUFFER_COMPLETE){
            LogMgr->logMessage("framebuffer error");
        }
        StateCache::setFrameBuffer(0);
        glBindTexture(GL_TEXTURE_2D,0);
        RHILogError("FrameBuffer::setDepthTexture");
    }

    void FrameBuffer::setDepthBuffer(DepthBufferPtr depth){
        if(mDepthTexture!=0)
            mDepthTexture=0;
        mDepthBuffer=depth;
        StateCache::setFrameBuffer(mID);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,depth->getID());
        if(depth->getStencil())
            glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_STENCIL_ATTACHMENT,GL_RENDERBUFFER,depth->getID());
        StateCache::setFrameBuffer(0);
        RHILogError("FrameBuffer::setDepthBuffer");
    }

    void FrameBuffer::blitTo(FrameBufferPtr dest,bool depth){
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER,dest->getID());
        glBindFramebuffer(GL_READ_FRAMEBUFFER,mID);
        glBlitFramebuffer(
            0,0,mWidth,mHeight,
            0,0,mWidth,mHeight,
            GL_COLOR_BUFFER_BIT,GL_LINEAR);
        glBindFramebuffer(GL_READ_FRAMEBUFFER,0);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);
        RHILogError("FrameBuffer::blitTo");
    }

    void FrameBuffer::checkDimension(TexturePtr tex){
        if(tex->getWidth()!=mWidth||tex->getHeight()!=mHeight){
            LogMgr->logMessage("framebuffer dimension not suitable");
        }
    }

}